﻿using System;
using System.Net;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Browser;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;

namespace SilverlightPlayground.LightBox
{
    public class SlideShowCoordinator : IApplicationService, INotifyPropertyChanged
    {
        public event EventHandler Initialize;
        public event EventHandler ImageChanged;

        private static SlideShowCoordinator current;

        /// <summary>
        /// Occurs when a property value changes.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Gets the current.
        /// </summary>
        /// <value>The current.</value>
        public static SlideShowCoordinator Current
        {
            get
            {
                if (current == null)
                    current = Application.Current.ApplicationLifetimeObjects
                        .OfType<SlideShowCoordinator>()
                        .FirstOrDefault();

                return current;
            }
        }

        private SlideShowImage currentImage;
        /// <summary>
        /// Gets or sets the current image.
        /// </summary>
        /// <value>The current image.</value>
        public SlideShowImage CurrentImage 
        {
            get { return this.currentImage; }
            private set
            {
                if (currentImage != value)
                {
                    currentImage = value;
                    this.RaisePropertyChanged("CurrentImage");

                    if (value != null && this.ImageChanged != null)
                        this.ImageChanged(this, EventArgs.Empty);
                }
            }
        }

        /// <summary>
        /// Gets or sets the images.
        /// </summary>
        /// <value>The images.</value>
        public ObservableCollection<SlideShowImage> Images { get; set; }

        /// <summary>
        /// Called by an application in order to initialize the application extension service.
        /// </summary>
        /// <param name="context">Provides information about the application state.</param>
        public void StartService(ApplicationServiceContext context)
        {
            if (!HtmlPage.IsEnabled)
                throw new Exception("HtmlBridge must be enabled to run the slideshow");

            this.Images = new ObservableCollection<SlideShowImage>();
            HtmlPage.RegisterScriptableObject("coordinator", this);
        }

        /// <summary>
        /// Called by an application in order to stop the application extension service.
        /// </summary>
        public void StopService()
        {
            this.Images.Clear();
            this.Images = null;
            this.CurrentImage = null;
        }

        /// <summary>
        /// Loads the specified collection name.
        /// </summary>
        /// <param name="collectionName">Name of the collection.</param>
        /// <param name="current">The current.</param>
        /// <param name="images">The images.</param>
        [ScriptableMember(ScriptAlias = "load")]
        public void Load(string collectionName, string current, ScriptObject images)
        {
            this.Images.Clear();

            while ((double)images.GetProperty("length") > 0)
            {
                ScriptObject obj = (ScriptObject)images.Invoke("pop");

                string uri = obj.GetProperty("uri") as string;

                Uri imageUri = new Uri(uri, UriKind.RelativeOrAbsolute);

                if (!imageUri.IsAbsoluteUri)
                    imageUri = new Uri(Application.Current.Host.Source, @"../" + imageUri);

                SlideShowImage ssi = new SlideShowImage
                    {
                        Title = obj.GetProperty("title") as string,
                        Uri = imageUri
                    };

                if (current == uri)
                    this.CurrentImage = ssi;

                this.Images.Insert(0, ssi);
            }

            this.RaisePositionChanged();

            if (this.Initialize != null)
                this.Initialize(this, EventArgs.Empty);
        }

        /// <summary>
        /// Raises the property changed.
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        private void RaisePropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = this.PropertyChanged;

            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }

        /// <summary>
        /// Moves the next.
        /// </summary>
        public bool MoveNext()
        {
            if (this.CurrentIndex != -1) 
                return this.GoTo(this.CurrentIndex + 1);
            
            return false;
        }

        /// <summary>
        /// Moves the previous.
        /// </summary>
        public bool MovePrevious()
        {
            if (this.CurrentIndex != -1) 
                return this.GoTo(this.CurrentIndex - 1);
            
            return false;
        }

        /// <summary>
        /// Goes to.
        /// </summary>
        /// <param name="index">The index.</param>
        public bool GoTo(int index)
        {
            if (this.CanGoTo(index))
            {
                this.CurrentImage = this.Images.ElementAt(index);
                this.RaisePositionChanged();
            }

            return true;
        }

        private void RaisePositionChanged()
        {
            this.RaisePropertyChanged("CurrentIndex");
            this.RaisePropertyChanged("CanMoveForward");
            this.RaisePropertyChanged("CanMoveBackward");
        }

        public bool CanMoveForward
        {
            get
            {
                return !(this.CurrentIndex == -1) && this.CanGoTo(this.CurrentIndex + 1);
            }
        }

        public bool CanMoveBackward
        {
            get
            {
                return !(this.CurrentIndex == -1) && this.CanGoTo(this.CurrentIndex - 1);
            }
        }

        public bool CanGoTo(int index)
        {
            return (index >= 0 && index < this.Images.Count);
        }

        /// <summary>
        /// Finds the index.
        /// </summary>
        /// <param name="slideShowImage">The slide show image.</param>
        /// <returns></returns>
        private int CurrentIndex
        {
            get
            {
                for (int i = 0; i < this.Images.Count; i++)
                    if (this.Images[i] == this.CurrentImage) return i;

                return -1;
            }
        }
    }
}